Skip to content

ci(desktop): add signed macOS canary build#2419

Merged
baxen merged 2 commits into
mainfrom
fizz/signed-canary-build
Jul 22, 2026
Merged

ci(desktop): add signed macOS canary build#2419
baxen merged 2 commits into
mainfrom
fizz/signed-canary-build

Conversation

@baxen

@baxen baxen commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Why

Testers need a Gatekeeper-valid build of current main without creating a release or updating existing installations.

What

  • Add a manual, main-only Apple Silicon workflow that signs and notarizes a DMG
  • Store the DMG as an unpublished seven-day Actions artifact with read-only repository permissions
  • Add a release-safety contract that requires workflow_dispatch to remain the only trigger
  • Document canary build/download usage and the artifact's public-repository visibility

Risk Assessment

Low — the workflow is manual-only and cannot create tags, GitHub Releases, or auto-updater assets. It does use the production Apple signing identity for explicitly requested canary builds; any signed-in GitHub user can download the artifact during its seven-day lifetime.

References

  • scripts/test-signed-canary-contract.sh
  • scripts/test-release-ref-contract.sh

Update Jul 22, 14:32: Addressed review feedback

  • Replaced the inaccurate "private artifact" wording with explicit visibility semantics
  • Tightened the contract from a partial trigger denylist to an only-workflow_dispatch assertion

Generated with Codex

Build, sign, and notarize a main-only Apple Silicon DMG without granting release publishing permissions or touching updater assets.

Co-authored-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
exit 1
fi

- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
@baxen
baxen marked this pull request as ready for review July 22, 2026 21:21
@baxen
baxen requested a review from a team as a code owner July 22, 2026 21:21

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d29bb97ecb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

echo "name=$NAME" >> "$GITHUB_OUTPUT"

- name: Upload signed canary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep signed canaries out of public artifacts

Because block/buzz is the OSS/public source repo, uploading the signed DMG with actions/upload-artifact does not make it private: GitHub's artifact docs say workflow artifacts can be downloaded by signed-in users with repository read access, which in a public repo is effectively any GitHub user. That exposes production-signed -test builds for the full retention window instead of limiting them to explicit testers, so this should use a genuinely access-controlled store or environment rather than a workflow artifact.

Useful? React with 👍 / 👎.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the workflow against release.yml and the release-safety contracts; ran both contract scripts locally at the PR head (d29bb97ec) — release ref contract passed / signed canary contract passed — and confirmed the branch contains current main.

What holds up well:

  • Publishing surface is genuinely zero: contents: read at both workflow and job level, no gh release, no TAURI_SIGNING_PRIVATE_KEY, createUpdaterArtifacts: false, and the new contract test in scripts/test-signed-canary-contract.sh is wired into CI via test-release-ref-contract.sh, so regressions fail ci.yml.
  • The -test.<run> prerelease version derivation sorts below the next real patch release under semver, so even a stray DMG can't masquerade as newer than a real release — and there's no updater artifact to feed the updater anyway.
  • Build steps faithfully mirror release.yml (mesh-llm rev via tomllib, llama cache keying, DMG text-size, entitlements staged to ${RUNNER_TEMP}/entitlements.plist for the codesign helper), plus it adds verify-macos-entitlements.sh to the post-sign checks.
  • Actions pinned by SHA, persist-credentials: false, zizmor green.
  • The RELEASING.md claim that the Release workflow "cannot build from main" is accurate — verify-release-ref.sh gates both the setup and build jobs on refs/tags/v<version>.

Two things worth a look:

  1. "Private ... Actions artifact" oversells it. block/buzz is a public repo; workflow-run artifacts on public repos are downloadable by any logged-in GitHub user (UI and API) for the retention window. So this ships a Gatekeeper-valid, production-identity-signed DMG that anyone can grab for 7 days. Probably acceptable — release DMGs are public anyway — but the PR body and RELEASING.md ("private Actions artifact") should say "short-lived" or "unpublished" rather than "private", so nobody relies on a confidentiality property that doesn't exist.

  2. The manual-only guard in the contract test has trigger gaps. grep -qE '^ (push|pull_request|schedule):' won't catch pull_request_target:, workflow_call:, workflow_run:, or repository_dispatch:. Suggest widening the alternation (or inverting: assert the on: block contains only workflow_dispatch). Cheap change, closes the loophole the test exists to guard.

Nit: minimumSystemVersion: 10.15 on an arm64-only build is a no-op (Apple Silicon floor is 11.0) — harmless, mirrors the release config.

Verdict: LGTM once the "private" wording is fixed; item 2 is a nice-to-have hardening.

Document the public visibility of short-lived Actions artifacts and require workflow_dispatch to remain the canary workflow’s only trigger.

Co-authored-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
@baxen
baxen enabled auto-merge (squash) July 22, 2026 21:32
@baxen
baxen merged commit c96ae0e into main Jul 22, 2026
25 checks passed
@baxen
baxen deleted the fizz/signed-canary-build branch July 22, 2026 21:43
loganj pushed a commit that referenced this pull request Jul 22, 2026
…ad-lifecycle

* origin/main:
  fix(desktop): strip GIF metadata extensions before upload (#2425)
  feat(desktop): gate sign-out behind key backup + typed confirmation (#2424)
  ci(desktop): add signed macOS canary build (#2419)
  feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122)
  Show team count separately in channel template rows (#2404)
  fix(dev): restore shared worktree identity from keyring (#2400)
  fix(onboarding): skip community profile setup for existing relay members (#2300)
  fix(mobile): preserve and display sidebar section icons (#2403)
  Unify sidebar chrome across themes (#2380)
  feat(media): add S3-truth per-community storage sweep (#2044)
brow pushed a commit that referenced this pull request Jul 22, 2026
…obile-releasing

Co-authored-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co>

Signed-off-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co>

* origin/main:
  fix(desktop): strip GIF metadata extensions before upload (#2425)
  feat(desktop): gate sign-out behind key backup + typed confirmation (#2424)
  ci(desktop): add signed macOS canary build (#2419)
  feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122)
  Show team count separately in channel template rows (#2404)
  fix(dev): restore shared worktree identity from keyring (#2400)
  fix(onboarding): skip community profile setup for existing relay members (#2300)
  fix(mobile): preserve and display sidebar section icons (#2403)
  Unify sidebar chrome across themes (#2380)
  feat(media): add S3-truth per-community storage sweep (#2044)
  feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests (#2206)

Co-authored-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1sv749mw8zcmld4ygjx2mx2aqcn3zvtuj2nlmgatxgad3t9uweu9q5marze <833d52edc71637f6d4889195b32ba0c4e2262f9254ffb47566475b15978ecf0a@sprout-oss.stage.blox.sqprod.co>

# Conflicts:
#	RELEASING.md
loganj pushed a commit that referenced this pull request Jul 22, 2026
…ad-lifecycle

* origin/main:
  fix(desktop): strip GIF metadata extensions before upload (#2425)
  feat(desktop): gate sign-out behind key backup + typed confirmation (#2424)
  ci(desktop): add signed macOS canary build (#2419)
  feat(desktop+acp): spawn a harness per (agent, community) pair at GUI startup — warm sockets, lazy LLM pool (#2122)
  Show team count separately in channel template rows (#2404)
  fix(dev): restore shared worktree identity from keyring (#2400)
  fix(onboarding): skip community profile setup for existing relay members (#2300)
  fix(mobile): preserve and display sidebar section icons (#2403)
  Unify sidebar chrome across themes (#2380)
  feat(media): add S3-truth per-community storage sweep (#2044)

Signed-off-by: npub1dpf98sl35hm9k65t8h6cvh5n6knn2msugh5k5nmysxwnw5wlh7uqn2wgp4 <685253c3f1a5f65b6a8b3df5865e93d5a7356e1c45e96a4f64819d3751dfbfb8@sprout-oss.stage.blox.sqprod.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants